package client

import (
	"context"
	"fmt"
	"net"
	"sync"
	"time"
	
	"inkjet168x-sdk-go/sdk/protocol/legacy"
	"inkjet168x-sdk-go/sdk/utils"
)

// UDPClientConfig UDP客户端配置
type UDPClientConfig struct {
	ServerAddr    string        // 服务器地址 (IP:Port)
	LocalAddr     string        // 本地绑定地址 (可选)
	Timeout       time.Duration // 操作超时时间
	RetryCount    int           // 重试次数
	RetryInterval time.Duration // 重试间隔
}

// DefaultConfig 返回默认配置
func DefaultConfig(serverAddr string) *UDPClientConfig {
	return &UDPClientConfig{
		ServerAddr:    serverAddr,
		LocalAddr:     "",
		Timeout:       5 * time.Second,
		RetryCount:    3,
		RetryInterval: 1 * time.Second,
	}
}

// UDPClient UDP通信客户端
type UDPClient struct {
	config     *UDPClientConfig
	conn       *net.UDPConn
	serverAddr *net.UDPAddr
	mu         sync.RWMutex // 保护并发访问
	closed     bool
}

// NewUDPClient 创建新的UDP客户端
func NewUDPClient(config *UDPClientConfig) (*UDPClient, error) {
	if config == nil {
		return nil, fmt.Errorf("config cannot be nil")
	}
	
	// 解析服务器地址
	serverAddr, err := net.ResolveUDPAddr("udp", config.ServerAddr)
	if err != nil {
		return nil, fmt.Errorf("failed to resolve server address %s: %w", config.ServerAddr, err)
	}
	
	client := &UDPClient{
		config:     config,
		serverAddr: serverAddr,
	}
	
	return client, nil
}

// Connect 建立UDP连接
func (c *UDPClient) Connect() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	
	if c.conn != nil {
		return nil // 已经连接
	}
	
	var localAddr *net.UDPAddr
	var err error
	
	// 如果指定了本地地址，则解析它
	if c.config.LocalAddr != "" {
		localAddr, err = net.ResolveUDPAddr("udp", c.config.LocalAddr)
		if err != nil {
			return fmt.Errorf("failed to resolve local address %s: %w", c.config.LocalAddr, err)
		}
	}
	
	// 创建UDP连接
	c.conn, err = net.DialUDP("udp", localAddr, c.serverAddr)
	if err != nil {
		return fmt.Errorf("failed to dial UDP %s: %w", c.serverAddr, err)
	}
	
	c.closed = false
	return nil
}

// Close 关闭连接
func (c *UDPClient) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	
	if c.conn == nil || c.closed {
		return nil
	}
	
	c.closed = true
	return c.conn.Close()
}

// SendPacket 发送数据包（旧格式，保持兼容性）
func (c *UDPClient) SendPacket(command uint8, data []byte) error {
	// 使用默认参数创建新格式数据包
	packet, err := legacy.NewPacket(
		legacy.Style_simhei,          // 默认字体(黑体)
		150,                            // 默认字号
		150,                            // 默认字宽
		0,                             // 默认字间隔
		0,                             // 默认旋转角度
		false,                         // 不加粗
		false,                         // 不斜体
		uint32(legacy.StyleSolid),   // 实体样式
		0,                             // X坐标
		0,                             // Y坐标
		string(data),                  // 文本内容
	)
	if err != nil {
		return fmt.Errorf("failed to create packet: %w", err)
	}
	return c.sendRawPacket(packet)
}

// SendTextPacket 发送新格式的文本数据包
func (c *UDPClient) SendTextPacket(fontName string, fontSize, fontWidth, charSpacing, rotation uint32,
	bold, italic bool, style uint32, x, y uint32, text string) error {
	
	packet, err := legacy.NewPacket(fontName, fontSize, fontWidth, charSpacing, rotation, bold, italic, style, x, y, text)
	if err != nil {
		return fmt.Errorf("failed to create text packet: %w", err)
	}
	return c.sendRawPacket(packet)
}

// SendPacketWithResponse 发送数据包并等待响应（旧格式）
func (c *UDPClient) SendPacketWithResponse(command uint8, data []byte) (*legacy.Packet, error) {
	ctx, cancel := context.WithTimeout(context.Background(), c.config.Timeout)
	defer cancel()
	
	return c.SendPacketWithResponseContext(ctx, command, data)
}

// SendPacketWithResponseContext 发送数据包并等待响应（带上下文，旧格式）
func (c *UDPClient) SendPacketWithResponseContext(ctx context.Context, command uint8, data []byte) (*legacy.Packet, error) {
	var lastErr error
	
	// 重试机制
	for i := 0; i <= c.config.RetryCount; i++ {
		if i > 0 {
			// 等待重试间隔
			select {
			case <-ctx.Done():
				return nil, ctx.Err()
			case <-time.After(c.config.RetryInterval):
			}
		}
		
		// 发送数据包（使用默认参数）
		packet, err := legacy.NewPacket(
			"Arial", 16, 16, 0, 0, false, false, uint32(legacy.StyleSolid), 0, 0, string(data))
		if err != nil {
			lastErr = fmt.Errorf("create packet failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		if err := c.sendRawPacket(packet); err != nil {
			lastErr = fmt.Errorf("send failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		// 等待响应
		response, err := c.receivePacketWithContext(ctx)
		if err != nil {
			lastErr = fmt.Errorf("receive failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		return response, nil
	}
	
	return nil, fmt.Errorf("all retry attempts failed: %w", lastErr)
}

// SendTextPacketWithResponse 发送新格式文本数据包并等待响应
func (c *UDPClient) SendTextPacketWithResponse(fontName string, fontSize, fontWidth, charSpacing, rotation uint32,
	bold, italic bool, style uint32, x, y uint32, text string) (*legacy.Packet, error) {
	
	ctx, cancel := context.WithTimeout(context.Background(), c.config.Timeout)
	defer cancel()
	
	return c.SendTextPacketWithResponseContext(ctx, fontName, fontSize, fontWidth, charSpacing, rotation, bold, italic, style, x, y, text)
}

// SendTextPacketWithResponseContext 发送新格式文本数据包并等待响应（带上下文）
func (c *UDPClient) SendTextPacketWithResponseContext(ctx context.Context, fontName string, fontSize, fontWidth, charSpacing, rotation uint32,
	bold, italic bool, style uint32, x, y uint32, text string) (*legacy.Packet, error) {
	
	var lastErr error
	
	// 重试机制
	for i := 0; i <= c.config.RetryCount; i++ {
		if i > 0 {
			// 等待重试间隔
			select {
			case <-ctx.Done():
				return nil, ctx.Err()
			case <-time.After(c.config.RetryInterval):
			}
		}
		
		// 创建并发送数据包
		packet, err := legacy.NewPacket(fontName, fontSize, fontWidth, charSpacing, rotation, bold, italic, style, x, y, text)
		if err != nil {
			lastErr = fmt.Errorf("create packet failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		if err := c.sendRawPacket(packet); err != nil {
			lastErr = fmt.Errorf("send failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		// 等待响应
		response, err := c.receivePacketWithContext(ctx)
		if err != nil {
			lastErr = fmt.Errorf("receive failed (attempt %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		return response, nil
	}
	
	return nil, fmt.Errorf("all retry attempts failed: %w", lastErr)
}

// sendRawPacket 发送原始数据包
func (c *UDPClient) sendRawPacket(packet *legacy.Packet) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return fmt.Errorf("connection not established")
	}
	
	if c.closed {
		return ErrConnectionClosed
	}
	
	data := packet.Marshal()
	
	// 设置写超时
	if err := c.conn.SetWriteDeadline(time.Now().Add(c.config.Timeout)); err != nil {
		return fmt.Errorf("failed to set write deadline: %w", err)
	}
	
	n, err := c.conn.Write(data)
	if err != nil {
		return fmt.Errorf("failed to write data: %w", err)
	}
	
	if n != len(data) {
		return fmt.Errorf("incomplete write: wrote %d bytes, expected %d", n, len(data))
	}
	
	return nil
}

// receivePacketWithContext 接收数据包（带上下文）
func (c *UDPClient) receivePacketWithContext(ctx context.Context) (*legacy.Packet, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return nil, fmt.Errorf("connection not established")
	}
	
	if c.closed {
		return nil, utils.ErrConnectionClosed
	}
	
	// 创建一个channel来接收结果
	type result struct {
		packet *legacy.Packet
		err    error
	}
	
	resultCh := make(chan result, 1)
	
	go func() {
		// 设置读超时
		deadline, ok := ctx.Deadline()
		if ok {
			if err := c.conn.SetReadDeadline(deadline); err != nil {
				resultCh <- result{nil, fmt.Errorf("failed to set read deadline: %w", err)}
				return
			}
		}
		
		// 读取数据
		buffer := make([]byte, 1024) // 假设最大包长度为1024字节
		n, err := c.conn.Read(buffer)
		if err != nil {
			resultCh <- result{nil, fmt.Errorf("failed to read data: %w", err)}
			return
		}
		
		// 解析数据包
		packet, err := legacy.Unmarshal(buffer[:n])
		if err != nil {
			resultCh <- result{nil, fmt.Errorf("failed to unmarshal packet: %w", err)}
			return
		}
		
		resultCh <- result{packet, nil}
	}()
	
	// 等待结果或上下文取消
	select {
	case res := <-resultCh:
		return res.packet, res.err
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

// IsConnected 检查连接状态
func (c *UDPClient) IsConnected() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	return c.conn != nil && !c.closed
}

// GetServerAddr 获取服务器地址
func (c *UDPClient) GetServerAddr() string {
	return c.config.ServerAddr
}

// GetLocalAddr 获取本地地址
func (c *UDPClient) GetLocalAddr() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return ""
	}
	
	return c.conn.LocalAddr().String()
}